#include "Common.h"

initSing(ScriptMgr);
initSing(HookMgr);

typedef void (*p)(ScriptMgr*);

void ScriptMgr::LoadScripts()
{
	new HookMgr;
	new LuaManager;
	CHAR tmp[MAX_PATH];
	GetCurrentDirectory(MAX_PATH, tmp);
	CHAR n_path[MAX_PATH];
	sprintf(n_path, "%s\\Bin", tmp);
	SetCurrentDirectory(n_path);
	WIN32_FIND_DATA fData;
	memset(&fData, NULL, sizeof(WIN32_FIND_DATA));
	HANDLE hFile = FindFirstFile("*.dll", &fData);
	if(!hFile)
	{
		SetCurrentDirectory(tmp);
		return;
	}

	do
	{
		HMODULE hMod = LoadLibrary(fData.cFileName);
		if(!hMod)
			continue;
		FARPROC prc = GetProcAddress(hMod, "_register");
		if(!prc)
		{
			Log->Notice("ScriptMgr", "DLL '%s', no _register-function found!!", fData.cFileName);
			FreeLibrary(hMod);
			continue;
		}
		p P = (p)prc;
		P(this);
		Log->Notice("ScriptMgr", "Loaded DLL '%s' at 0x%p! All functions are working :)!", fData.cFileName, hMod);
	}
	while(FindNextFile(hFile, &fData));
	SetCurrentDirectory(tmp);
	LuaManager::getSingle()->Load();
}

void ScriptMgr::register_hook(Hooks hook, void* functionptr)
{
	sHookMgr->HookList[hook].insert(functionptr);
}

void ScriptMgr::register_hook(IEventReceiver* eventholder)
{
	sHookMgr->m_events.insert(eventholder);
}

void ScriptMgr::register_command(char* cmd, script_command proc)
{
	ChatCommands.insert(make_pair(cmd, proc));
}

bool ScriptMgr::ParseCommand(char* cmd, char* args, Player* sender)
{
	if(!ChatCommands.size())
		return false;
	map<char*, script_command>::iterator itr = ChatCommands.begin();
	map<char*, script_command>::iterator end = ChatCommands.end();

	for( ; itr != end; ++itr)
	{
		if(!strcmp(cmd, itr->first))
		{
			itr->second(args, sender);
			return true;			
		}
	}
	return false;
}

GossipScript* ScriptMgr::GetScriptForCreature(ui32 id)
{
	map<ui32, GossipScript*>::iterator itr = m_cgossipscripts.begin();
	map<ui32, GossipScript*>::iterator end = m_cgossipscripts.end();

	for( ; itr != end; ++itr)
	{
		if(itr->first == id)
			return itr->second;
	}
	return 0;
}

void ScriptMgr::register_creature_gossip(ui32 id, GossipScript* gs)
{
	m_cgossipscripts.insert(make_pair(id, gs));
}

void ScriptMgr::register_creature_script(ui32 id, CreatureScript*(*func)(Creature*))
{
	m_cscripts[id] = func;
}

CreatureScript* ScriptMgr::GetNewScriptForCreature(Creature* npc)
{
	CreatureScript*(*create)(Creature*) = m_cscripts[npc->GetEntry()];
	if(!create)
		return 0;
	return create(npc);
}

bool HookMgr::OnAccountLogin(const char* accname, const char* ip)
{
	return true;
}

void HookMgr::OnNewCharacter(Player* plr)
{
	set<void*>::iterator itr = HookList[ON_NEW_CHAR].begin();
	set<void*>::iterator end = HookList[ON_NEW_CHAR].end();

	for( ; itr != end; ++itr)
	{
		on_new_char chr = (on_new_char)(*itr);
		chr(plr);
	}

	set<IEventReceiver*>::iterator evitr = m_events.begin();
	set<IEventReceiver*>::iterator evend = m_events.end();

	for( ; evitr != evend; ++evitr)
		(*evitr)->OnNewChar(plr);
}

void HookMgr::OnCharLogin(Player* plr)
{
	set<void*>::iterator itr = HookList[ON_CHAR_LOGIN].begin();
	set<void*>::iterator end = HookList[ON_CHAR_LOGIN].end();

	for( ; itr != end; ++itr)
	{
		on_char_login chr = (on_char_login)(*itr);
		chr(plr);
	}

	set<IEventReceiver*>::iterator evitr = m_events.begin();
	set<IEventReceiver*>::iterator evend = m_events.end();

	for( ; evitr != evend; ++evitr)
		(*evitr)->OnCharLogin(plr);
}

void HookMgr::OnAreaChanged(ui32 areaid, Player* pPlayer)
{
	set<void*>::iterator itr = HookList[ON_AREA_CHANGED].begin();
	set<void*>::iterator end = HookList[ON_AREA_CHANGED].end();

	for( ; itr != end; ++itr)
	{
		on_area_changed chr = (on_area_changed)(*itr);
		chr(areaid, pPlayer);
	}

	set<IEventReceiver*>::iterator evitr = m_events.begin();
	set<IEventReceiver*>::iterator evend = m_events.end();

	for( ; evitr != evend; ++evitr)
		(*evitr)->OnAreaChanged(areaid, pPlayer);
}

void GossipScript::GossipHello(Player* pSender, Object* pObject)
{
	if(pObject->GetTypeId() == TYPEID_UNIT)
	{
		TextRelation* rel = miscmgr->GetTextRelation(pObject->GetEntry());
		ui32 textid = 1;
		if(rel)
			textid = rel->textid;
		GossipMenu* menu = new GossipMenu(textid, pObject->GetGUID());
		menu->Send(pSender);
	}
}

void GossipScript::GossipSelect(Player* pSender, Object* pObject, ui32 MenuId, char* msg)
{
}

void GossipScript::OnRegister(Object* pReceiver)
{
}

GossipMenuItem* GossipMenu::AddMenuItem(ui8 icon, char* text, ui32 id)
{
	GossipMenuItem* im = new GossipMenuItem();
	im->icon = icon;
	im->iid = id;
	im->id = m_items.size() + 1;
	im->text = text;
	im->clickprice = 0;
	im->boxmessage = "";
	m_items.insert(m_items.end(), im);
	return im;
}

GossipMenu::GossipMenu(ui32 textid, ui64 guid)
{
	this->textid = textid;
	this->guid = guid;
}

void GossipMenu::Send(Player* target)
{
	RealmPacket data(SMSG_GOSSIP_MESSAGE, 0);
	data << guid << ui32(0);
	data << textid << m_items.size();
	set<GossipMenuItem*>::iterator itr = m_items.begin();
	set<GossipMenuItem*>::iterator end = m_items.end();

	for( ; itr != end; ++itr)
	{
		GossipMenuItem* im = (*itr);
		data << im->id << im->icon << ui8(im->textbox) << im->clickprice << im->text << im->boxmessage;
	}
	data << ui32(0);
	target->GetSession()->SendPacket(&data);
	target->m_openedmenu = this;
}

GossipMenuItem* GossipMenu::GetItem(ui32 id)
{
	if(id > m_items.size())
		return NULL;
	set<GossipMenuItem*>::iterator itr = m_items.begin();
	set<GossipMenuItem*>::iterator end = m_items.end();

	for( ; itr != end; ++itr)
		if((*itr)->id == id)
			return (*itr);
	return NULL;
}